package com.ubxtech.db.aspect;

import com.ubxtech.core.context.ContextConstants;
import com.ubxtech.core.context.ContextUtil;
import com.ubxtech.db.annotation.IgnoreTenant;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 在方法上单独设置要不要多租户查询,设置了多租户查询也可以查询所有数据
 * @author Victor.Xiao
 * @since 2023-08-14 10:27
 **/
@Aspect
@Slf4j
@Component
public class MybatisPlusTenantIgnoreAspect {
    /**
     * 切入点
     */
    @Pointcut("@within(com.ubxtech.db.annotation.IgnoreTenant) ||@annotation(com.ubxtech.db.annotation.IgnoreTenant)")
    public void tenantIgnore() {
    }

    @Around("tenantIgnore()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Class<?> targetClass = point.getTarget().getClass();
        //这里要和client的区分,否则方法里面再调用client也会监听到,会清空KEY_IGNORE_TENANT_FLAG标志
        if (targetClass.getName().contains("com.sun.proxy")) {
            //如果是client的代理类,直接返回,client的IgnoreTenant只在FeignAddHeaderRequestInterceptor处理
            return point.proceed();
        }
        try {
            IgnoreTenant classIgnoreTenant = targetClass.getAnnotation(IgnoreTenant.class);
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            IgnoreTenant methodIgnoreTenant = method.getAnnotation(IgnoreTenant.class);

            //判断类上是否有注解
            boolean isClassAnnotated = AnnotationUtils.isAnnotationDeclaredLocally(IgnoreTenant.class, targetClass);
            //如果类上有
            if (isClassAnnotated) {
                ContextUtil.setIgnoreTenantFlag(classIgnoreTenant.isIgnore());
            }
            //如果方法上有 以方法上的为主
            if (methodIgnoreTenant != null) {
                ContextUtil.setIgnoreTenantFlag(methodIgnoreTenant.isIgnore());
            }
            return point.proceed();
        }finally {
            //同一线程,多个查询需清空
            ContextUtil.remove(ContextConstants.KEY_IGNORE_TENANT_FLAG);
        }
    }
}
